using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using MoonFramework.Template;

namespace MoonFramework.Scripts.Pool
{
	/// <summary>
	/// 泛型对象池管理器
	/// </summary>
	public class ObjPoolManager : BaseManager<ObjPoolManager>
	{
		private readonly Dictionary<string, PoolNode> pool = new();

		/// <summary>
		/// 缓存池节点
		/// </summary>
		private class PoolNode
		{
			private readonly Stack<object> _poolStack = new();

			public void Push(object obj)
				=> _poolStack.Push(obj);

			public void Clear() => _poolStack.Clear();

			public object Pop()
				=> _poolStack.Pop();

			public int Count => _poolStack.Count;
		}

		/// <summary>
		/// 从对象池获取对象
		/// </summary>
		/// <param name="objectFactory">对象创建工厂</param>
		/// <param name="callback">获取对象后的回调</param>
		public async UniTask<T> PopAsync<T>(Func<UniTask<T>> objectFactory = null, Action<T> callback = null) where T : class
		{
			T obj;
			if (pool.TryGetValue(typeof(T).FullName ?? string.Empty, out var poolNode) && poolNode.Count > 0)
			{
				obj = poolNode.Pop() as T;
				callback?.Invoke(obj);
			}
			else
			{
				obj = await objectFactory();
				callback?.Invoke(obj);
			}
			return obj;
		}

		public T Pop<T>(Func<T> objectFactory, Action<T> callback = null) where T : class
		{
			T obj;
			if (pool.TryGetValue(typeof(T).FullName ?? string.Empty, out var poolNode) && poolNode.Count > 0)
			{
				obj = poolNode.Pop() as T;
				callback?.Invoke(obj);
			}
			else
			{
				obj = objectFactory();
				callback?.Invoke(obj);
			}
			return obj;
		}

		/// <summary>
		/// 将对象归还到池中
		/// </summary>
		/// <param name="obj">要归还的对象</param>
		public void Push(object obj)
		{
			if (!pool.TryGetValue(obj.GetType().FullName ?? string.Empty, out var poolNode))
			{
				poolNode = new PoolNode();
				pool[obj.GetType().FullName ?? string.Empty] = poolNode;
			}
			poolNode.Push(obj);
		}

		/// <summary>
		/// 预加载对象池
		/// </summary>
		/// <param name="count">预加载数量</param>
		/// <param name="objectFactory">对象创建工厂</param>
		public async UniTask AllocateAsync<T>(int count, Func<UniTask<T>> objectFactory)
		{
			var type = typeof(T).FullName;
			if (!pool.TryGetValue(type ?? string.Empty, out var poolNode))
			{
				poolNode = new PoolNode();
				pool[type ?? string.Empty] = poolNode;
			}

			// 异步预加载指定数量的对象
			for (int i = 0; i < count; i++)
			{
				var obj = await objectFactory();
				poolNode.Push(obj);
			}
		}

		public void Allocate<T>(int count, Func<T> objectFactory)
		{
			string type = typeof(T).FullName;
			if (!pool.TryGetValue(type ?? string.Empty, out var poolNode))
			{
				poolNode = new PoolNode();
				pool[type ?? string.Empty] = poolNode;
			}
			for (int i = 0; i < count; i++)
			{
				var obj = objectFactory();
				poolNode.Push(obj);
			}
		}

		/// <summary>
		/// 清空对象池
		/// </summary>
		public void Clear()
		{
			foreach (var type in pool.Keys)
				RemoveType(type);
			pool.Clear();
		}

		/// <summary>
		/// 移除指定类型的对象池
		/// </summary>
		public void RemoveType<T>()
		{
			string type = typeof(T).FullName;
			if (pool.TryGetValue(type ?? string.Empty, out var poolNode))
			{
				poolNode.Clear();
				pool.Remove(type, out poolNode);
			}
		}
		
		private void RemoveType(string type)
		{
			if (pool.TryGetValue(type, out var poolNode))
			{
				poolNode.Clear();
				pool.Remove(type, out poolNode);
			}
		}
	}
}
